
package com.hlkj.pay.app.merchant.ext.impl.helipay.handler;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.io.IOException;
import java.util.*;

import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.id.IdUtils;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.ext.dto.report.ChannelMerchantReportContext;
import com.hlkj.pay.app.merchant.ext.impl.MerchantAccessUploadFile;
import com.hlkj.pay.app.merchant.ext.impl.helipay.dto.HeliPayEatrxConfig;
import com.hlkj.pay.app.merchant.ext.impl.helipay.dto.eatrx.FileAttachmentReq;
import com.hlkj.pay.app.merchant.ext.impl.helipay.dto.eatrx.FileAttachmentRes;
import com.hlkj.pay.common.MerchantResultCode;
import com.hlkj.pay.dto.merchant.report.MerchantReportDto;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.infrastructure.model.merchant.*;
import com.hlkj.pay.infrastructure.model.pay.PayChannelRequestDO;
import com.hlkj.pay.util.FileUtils;

import cn.hutool.core.codec.Base64Encoder;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.StringPool;

/**
 * 汇付 商户进件参数处理
 * 
 * @author HlpayTeam
 * @date 2024/09/26 12:02
 */
@Slf4j
@Service
public class HeliPayMerchantEatrxParamsHandle extends HeliPayMerchantEatrxCommonParamsHandle {

    /**
     * 企业商户进件-新增参数组装
     *
     * @param channelMerchantAccessContext
     * @return
     */
    public CommonResult<Void> merchantReportParamsCheck(ChannelMerchantReportContext channelMerchantAccessContext) {
        MerchantReportDto merchantReportDto = channelMerchantAccessContext.getMerchantReportDto();
        MerchantReportBusinessDO merchantReportBusiness = merchantReportDto.getMerchantReportBusiness();
        MerchantReportInfoDO merchantReportInfo = merchantReportDto.getMerchantReportInfo();
        MerchantCertInfoDO merchantReportLegal = merchantReportDto.getMerchantReportLegal();
        MerchantCertInfoDO merchantReportContact = merchantReportDto.getMerchantReportContact();
        MerchantCardDO merchantReportCard = merchantReportDto.getMerchantReportCard();
        MerchantLicenseDO merchantReportLicense = merchantReportDto.getMerchantReportLicense();
        switch (MerchantEnum.MERCHANT_TYPE.from(merchantReportInfo.getType())) {
            case PERSONAL:
                break;
            case COMPANY:
                if (!"1".equals(merchantReportLegal.getCertType())) {
                    return CommonResult.error(MerchantResultCode.MERCHANT_ACCESS_PARAMS_ERROR.getCode(),
                            MerchantResultCode.MERCHANT_ACCESS_PARAMS_ERROR.getMsg() + "合利宝 报备证件类型只支持身份证");
                }
                break;
        }

        return CommonResult.success();
    }

    /**
     * 企业商户进件-新增参数组装
     *
     * @param channelMerchantReportContext
     * @return
     */
    public Map<String, Object> merchantReportAddParams(ChannelMerchantReportContext channelMerchantReportContext) {
        Map<String, Object> params = new HashMap<>();
        MerchantReportDto merchantReportDto = channelMerchantReportContext.getMerchantReportDto();
        MerchantReportBusinessDO merchantReportBusiness = merchantReportDto.getMerchantReportBusiness();
        MerchantReportInfoDO merchantReportInfo = merchantReportDto.getMerchantReportInfo();
        MerchantCertInfoDO merchantReportLegal = merchantReportDto.getMerchantReportLegal();
        MerchantCertInfoDO merchantReportContact = merchantReportDto.getMerchantReportContact();
        MerchantCardDO merchantReportCard = merchantReportDto.getMerchantReportCard();
        MerchantLicenseDO merchantReportLicense = merchantReportDto.getMerchantReportLicense();
        params.put("userId", merchantReportInfo.getUserId());
        params.put("realName", merchantReportLicense.getName());
        params.put("shortName", merchantReportBusiness.getShortName());
        params.put("certType", "BUSINESSLICENSE");
        params.put("certNo", merchantReportLicense.getLicenseCode());
        params.put("address", merchantReportLicense.getAddress());
        params.put("certExpireStartDate", date(merchantReportLicense.getLicenseBeginDate()));
        params.put("certExpireEndDate", dateEnd(merchantReportLicense.getLicenseValidityType(), merchantReportLicense.getLicenseEndDate()));
        switch (merchantReportLicense.getCompanyType()) {
            case "5":
                params.put("merchantType", "INDIVIDUALBISS");
                break;
            default:
                params.put("merchantType", "ENTERPRISE");
        }
        params.put("legalPerson", merchantReportLegal.getName());
        params.put("personCertType", "IDCARD");
        params.put("legalPersonId", merchantReportLegal.getCertNo());
        params.put("personIdExpireStartDate", date(merchantReportLegal.getCertBeginDate()));
        params.put("personIdExpireEndDate", dateEnd(merchantReportLegal.getCertValidityType(), merchantReportLegal.getCertEndDate()));
        params.put("phone", merchantReportLegal.getPhone());
        params.put("contactName", merchantReportContact.getName());
        params.put("contactCertType", "IDCARD");
        params.put("contactPersonId", merchantReportContact.getCertNo());
        params.put("contactExpireStartDate", date(merchantReportContact.getCertBeginDate()));
        params.put("contactExpireEndDate", dateEnd(merchantReportContact.getCertValidityType(), merchantReportContact.getCertEndDate()));
        params.put("customerPhone", merchantReportContact.getPhone());
        params.put("email", merchantReportLegal.getOtherValue());
        params.put("notifyUrl", channelMerchantReportContext.getNotifyUrl());
        params.put("orderNum", merchantReportInfo.getRequestId());
        params.put("password", channelMerchantReportContext.getPassword());

        Map<String, String> settleAccount = new HashMap<>();
        settleAccount.put("bankAccountName", merchantReportCard.getName());
        settleAccount.put("bankAccountNo", merchantReportCard.getCardNo());
        switch (MerchantEnum.CARD_TYPE.from(merchantReportCard.getType())) {
            case CORPORATE_ACCOUNT:
                settleAccount.put("settleBankType", "TOPUBLIC");
                settleAccount.put("bankNo", merchantReportCard.getBranchCode());
                settleAccount.put("notifyUrl", channelMerchantReportContext.getSettleAccountNotifyUrl());
                break;
            default:
                settleAccount.put("settleBankType", "TOPRIVATE");
        }
        params.put("settleAccount", settleAccount);
        List<MerchantAccessUploadFile> merchantAccessUploadFiles = channelMerchantReportContext.getMerchantAccessUploadFiles();
        if (!CollectionUtils.isEmpty(merchantAccessUploadFiles)) {
            merchantAccessUploadFiles.forEach(merchantAccessUploadFile -> {
                if (StringUtils.hasText(merchantAccessUploadFile.getFileId())) {
                    params.put(merchantAccessUploadFile.getFieldName(), merchantAccessUploadFile.getFileId());
                }
            });
        }
        return params;
    }

    public Map<String, Object> merchantReportPersonalAddParams(ChannelMerchantReportContext channelMerchantReportContext) {
        Map<String, Object> params = new HashMap<>();
        MerchantReportDto merchantReportDto = channelMerchantReportContext.getMerchantReportDto();
        MerchantReportInfoDO merchantReportInfo = merchantReportDto.getMerchantReportInfo();
        MerchantCertInfoDO merchantReportLegal = merchantReportDto.getMerchantReportLegal();
        MerchantCardDO merchantReportCard = merchantReportDto.getMerchantReportCard();
        params.put("userId", merchantReportInfo.getUserId());
        params.put("realName", merchantReportLegal.getName());
        params.put("certType", "IDCARD");
        params.put("certNo", merchantReportLegal.getCertNo());
        params.put("certAddress", merchantReportLegal.getAddress());
        params.put("certExpireStartDate", date(merchantReportLegal.getCertBeginDate()));
        params.put("certExpireEndDate", dateEnd(merchantReportLegal.getCertValidityType(), merchantReportLegal.getCertEndDate()));
        params.put("phone", merchantReportLegal.getPhone());
        params.put("orderNum", merchantReportInfo.getRequestId());
        params.put("password", channelMerchantReportContext.getPassword());
        Map<String, String> settleAccount = new HashMap<>();
        settleAccount.put("bankAccountName", merchantReportCard.getName());
        settleAccount.put("bankAccountNo", merchantReportCard.getCardNo());
        params.put("settleAccount", settleAccount);
        List<MerchantAccessUploadFile> merchantAccessUploadFiles = channelMerchantReportContext.getMerchantAccessUploadFiles();
        Set<String> fileNames = new HashSet<>() {

            {
                add("certFrontSideId");
                add("certBackSideId");
            }
        };
        if (!CollectionUtils.isEmpty(merchantAccessUploadFiles)) {
            merchantAccessUploadFiles.forEach(merchantAccessUploadFile -> {
                if (fileNames.contains(merchantAccessUploadFile.getFieldName()) && StringUtils.hasText(merchantAccessUploadFile.getFileId())) {
                    params.put(merchantAccessUploadFile.getFieldName(), merchantAccessUploadFile.getFileId());
                }
            });
        }
        return params;
    }

    public Map<String, Object> merchantReportUpdateParams(ChannelMerchantReportContext channelMerchantReportContext) {
        Map<String, Object> params = new HashMap<>();
        MerchantReportDto merchantReportDto = channelMerchantReportContext.getMerchantReportDto();
        MerchantCertInfoDO merchantReportLegal = merchantReportDto.getMerchantReportLegal();
        MerchantCardDO merchantReportCard = merchantReportDto.getMerchantReportCard();
        MerchantLicenseDO merchantReportLicense = merchantReportDto.getMerchantReportLicense();
        MerchantReportInfoDO merchantReportInfo = merchantReportDto.getMerchantReportInfo();
        params.put("userId", merchantReportInfo.getUserId());
        params.put("operateType", "REDO");
        params.put("address", merchantReportLicense.getAddress());
        params.put("certExpireStartDate", date(merchantReportLicense.getLicenseBeginDate()));
        params.put("certExpireEndDate", dateEnd(merchantReportLicense.getLicenseValidityType(), merchantReportLicense.getLicenseEndDate()));
        switch (merchantReportLicense.getCompanyType()) {
            case "5":
                params.put("merchantType", "INDIVIDUALBISS");
                break;
            default:
                params.put("merchantType", "ENTERPRISE");
        }
        params.put("legalPerson", merchantReportLegal.getName());
        params.put("personCertType", "IDCARD");
        params.put("legalPersonId", merchantReportLegal.getCertNo());
        params.put("personIdExpireStartDate", date(merchantReportLegal.getCertBeginDate()));
        params.put("personIdExpireEndDate", dateEnd(merchantReportLegal.getCertValidityType(), merchantReportLegal.getCertEndDate()));
        params.put("phone", merchantReportLegal.getPhone());
        params.put("password", channelMerchantReportContext.getPassword());
        Map<String, String> settleAccount = new HashMap<>();
        settleAccount.put("bankAccountName", merchantReportCard.getName());
        settleAccount.put("bankAccountNo", merchantReportCard.getCardNo());
        switch (MerchantEnum.CARD_TYPE.from(merchantReportCard.getType())) {
            case CORPORATE_ACCOUNT:
                settleAccount.put("settleBankType", "TOPUBLIC");
                settleAccount.put("bankNo", merchantReportCard.getBranchCode());
                settleAccount.put("notifyUrl", channelMerchantReportContext.getSettleAccountNotifyUrl());
                break;
            default:
                settleAccount.put("settleBankType", "TOPRIVATE");
        }
        params.put("settleAccount", settleAccount);
        List<MerchantAccessUploadFile> merchantAccessUploadFiles = channelMerchantReportContext.getMerchantAccessUploadFiles();
        if (!CollectionUtils.isEmpty(merchantAccessUploadFiles)) {
            merchantAccessUploadFiles.forEach(merchantAccessUploadFile -> {
                if (StringUtils.hasText(merchantAccessUploadFile.getFileId())) {
                    params.put(merchantAccessUploadFile.getFieldName(), merchantAccessUploadFile.getFileId());
                }
            });
        }
        return params;
    }

    public Map<String, Object> merchantReportPersonalUpdateParams(ChannelMerchantReportContext channelMerchantReportContext) {
        Map<String, Object> params = new HashMap<>();
        MerchantReportDto merchantReportDto = channelMerchantReportContext.getMerchantReportDto();
        MerchantReportInfoDO merchantReportInfo = merchantReportDto.getMerchantReportInfo();
        MerchantCertInfoDO merchantReportLegal = merchantReportDto.getMerchantReportLegal();
        MerchantCardDO merchantReportCard = merchantReportDto.getMerchantReportCard();
        params.put("userId", merchantReportInfo.getUserId());
        params.put("operateType", "REDO");
        params.put("certExpireStartDate", date(merchantReportLegal.getCertBeginDate()));
        params.put("certExpireEndDate", dateEnd(merchantReportLegal.getCertValidityType(), merchantReportLegal.getCertEndDate()));
        params.put("phone", merchantReportLegal.getPhone());
        params.put("orderNum", merchantReportInfo.getRequestId());
        params.put("password", channelMerchantReportContext.getPassword());
        Map<String, String> settleAccount = new HashMap<>();
        settleAccount.put("bankAccountName", merchantReportCard.getName());
        settleAccount.put("bankAccountNo", merchantReportCard.getCardNo());
        params.put("settleAccount", settleAccount);
        List<MerchantAccessUploadFile> merchantAccessUploadFiles = channelMerchantReportContext.getMerchantAccessUploadFiles();
        Set<String> fileNames = new HashSet<>() {

            {
                add("certFrontSideId");
                add("certBackSideId");
            }
        };
        if (!CollectionUtils.isEmpty(merchantAccessUploadFiles)) {
            merchantAccessUploadFiles.forEach(merchantAccessUploadFile -> {
                if (fileNames.contains(merchantAccessUploadFile.getFieldName()) && StringUtils.hasText(merchantAccessUploadFile.getFileId())) {
                    params.put(merchantAccessUploadFile.getFieldName(), merchantAccessUploadFile.getFileId());
                }
            });
        }
        return params;
    }

    /**
     * 新增文件参数转换
     *
     * @param channelMerchantAccessContext
     */
    public void addProcessFileId(ChannelMerchantReportContext channelMerchantAccessContext, HeliPayEatrxConfig heliPayEatrxConfig) {
        MerchantReportDto merchantAccessDto = channelMerchantAccessContext.getMerchantReportDto();
        MerchantLicenseDO merchantAccessLicense = merchantAccessDto.getMerchantReportLicense();
        MerchantCertInfoDO merchantAccessCert = merchantAccessDto.getMerchantReportLegal();
        MerchantCardDO merchantAccessCard = merchantAccessDto.getMerchantReportCard();
        PayChannelRequestDO beforeMerchantAccessRequestDO = channelMerchantAccessContext.getBeforePayChannelRequestDO();
        MerchantReportBusinessDO merchantAccessBusiness = merchantAccessDto.getMerchantReportBusiness();
        MerchantReportInfoDO merchantAccessInfo = merchantAccessDto.getMerchantReportInfo();
        MerchantCertInfoDO merchantAccessContact = merchantAccessDto.getMerchantReportContact();
        // 配置转换
        boolean test = channelMerchantAccessContext.isTest();
        Map<String, String> fileMap = new HashMap<>();
        if (beforeMerchantAccessRequestDO != null && StringUtils.hasText(beforeMerchantAccessRequestDO.getFileParams())) {
            fileMap = JsonUtils.parseObject(beforeMerchantAccessRequestDO.getFileParams(), Map.class);
        }
        try {
            // 营业执照 01
            // 开户许可证/开户证明照 02
            // 门头照 03
            // 店内场景照 04
            // 收银台照 05
            // 法人身份证正面照 06
            // 法人身份证反面照 07
            // 联系人身份证正面照 08
            // 联系人身份证反面照 09
            // 公司大楼照 10
            // 公司前台照 11
            // 结算银行卡正面照 12
            // 结算银行卡反面照 13
            // 结算人手持银行卡正面照 14
            // 经营者身份证正面照 15
            // 经营者身份证反面照 16
            // 经营者手持身份证正面照 17
            // 经营者手持银行卡正面照 18
            // 其它图片1 19
            // 其它图片2 20
            // 开户意愿视频 50
            // 分账协议 52
            List<MerchantAccessUploadFile> merchantAccessUploadFiles = new ArrayList<>();
            if (merchantAccessLicense != null) {
                merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileUrl(merchantAccessLicense.getLicenseUrl()).fieldName("customerCertPid").build());
            }
            merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileUrl(merchantAccessCert.getCertFrontUrl()).fieldName("certFrontSideId").build());
            merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileUrl(merchantAccessCert.getCertBackUrl()).fieldName("certBackSideId").build());
            merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileUrl(merchantAccessContact.getCertFrontUrl()).fieldName("contactCertFrontSideId").build());
            merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileUrl(merchantAccessContact.getCertBackUrl()).fieldName("contactCertBackSideId").build());

            for (MerchantAccessUploadFile merchantAccessUploadFile : merchantAccessUploadFiles) {
                CommonResult<Void> f07 = fileUploadProcess(fileMap, heliPayEatrxConfig, merchantAccessUploadFile, test);
                if (!f07.isSuccess()) {
                    channelMerchantAccessContext.setProcessStatus(Boolean.FALSE);
                    channelMerchantAccessContext.setRemark(f07.getMsg());
                    return;
                }
            }
            channelMerchantAccessContext.setMerchantAccessUploadFiles(merchantAccessUploadFiles);
        }
        catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        finally {
            PayChannelRequestDO payChannelRequestDO = channelMerchantAccessContext.getPayChannelRequestDO();
            if (payChannelRequestDO == null) {
                payChannelRequestDO = new PayChannelRequestDO();
            }
            payChannelRequestDO.setFileParams(JsonUtils.toJsonString(fileMap));
            channelMerchantAccessContext.setPayChannelRequestDO(payChannelRequestDO);
        }
    }

    public CommonResult<Void> fileUploadProcess(Map<String, String> fileMap, HeliPayEatrxConfig heliPayEatrxConfig, MerchantAccessUploadFile merchantAccessUploadFile,
            boolean test) {
        if (!StringUtils.hasText(merchantAccessUploadFile.getFileUrl())) {
            return CommonResult.success();
        }
        String fileKey = merchantAccessUploadFile.getFileUrl().hashCode() + "_" + merchantAccessUploadFile.getFileKey();
        String fileId = fileMap.get(fileKey);
        if (StringUtils.hasText(fileId)) {
            log.info("helipay文件映射获取成功 fileUrl:{},fileId:{}", merchantAccessUploadFile.getFileUrl(), fileId);
            merchantAccessUploadFile.setFileId(fileId);
            return CommonResult.success();
        }
        log.info("helipay文件映射获取未成功 fileType:{}, fileUrl:{}", test, merchantAccessUploadFile.getFileUrl());
        CommonResult<Void> f371 = fileUpload(merchantAccessUploadFile, heliPayEatrxConfig, test);
        if (f371.isSuccess()) {
            fileMap.put(fileKey, merchantAccessUploadFile.getFileId());
        }
        return f371;
    }

    /**
     * 文件上传
     *
     * @param merchantAccessUploadFile
     * @param heliPayEatrxConfig
     * @return
     * @throws Exception
     */
    public CommonResult<Void> fileUpload(MerchantAccessUploadFile merchantAccessUploadFile, HeliPayEatrxConfig heliPayEatrxConfig, boolean test) {
        if (!file(merchantAccessUploadFile.getFileUrl())) {
            log.info("文件格式错误 跳过文件上传:fileUrl:{},test:{}", merchantAccessUploadFile.getFileUrl(), test);
            return CommonResult.success();
        }
        try {
            byte[] bytes = FileUtils.fileBytes(merchantAccessUploadFile.getFileUrl());
            String base64Str = Base64Encoder.encode(bytes);
            FileAttachmentReq fileAttachmentReq = new FileAttachmentReq();
            fileAttachmentReq.setPic(base64Str);
            fileAttachmentReq.setOrderNum(IdUtils.fastSimpleUUID());
            String url = url(test) + "/ea/photoUpload.action";
            CommonResult<FileAttachmentRes> commonResult = productRequest(fileAttachmentReq, url, FileAttachmentRes.class, heliPayEatrxConfig);
            if (commonResult.isSuccess()) {
                FileAttachmentRes fileAttachmentRes = commonResult.getData();
                if (fileAttachmentRes.success()) {
                    merchantAccessUploadFile.setFileId(fileAttachmentRes.getPicId());
                    return CommonResult.success();
                }
                else {
                    return CommonResult.error(1, fileAttachmentRes.getRetMsg());
                }
            }
            return CommonResult.error(commonResult.getCode(), commonResult.getMsg());
        }
        catch (IOException e) {
            return CommonResult.error(1, e.getMessage());
        }
    }

    public static boolean file(String fileUrl) {
        if (!StringUtils.hasText(fileUrl)) {
            return false;
        }
        int indexOf = fileUrl.lastIndexOf(StringPool.SLASH);
        if (indexOf < 0) {
            return false;
        }
        String fileType = fileUrl.substring(indexOf);
        if (!fileType.contains(StringPool.DOT)) {
            return false;
        }
        return true;
    }

}
